/*
   Copyright 2022 cmanlh

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
import JscConfig from './config.js';
import JscUtil from './util.js';
export default class JscDialog extends HTMLElement {
    static get observedAttributes() { return [] }
    static #dialogCache = [];

    static #returnDialog(dialog) {
        JscDialog.#dialogCache.push(dialog);
    }

    static show(options) {
        let dialog = JscDialog.#dialogCache.pop();
        if (null == dialog) {
            dialog = document.createElement('jsc-dialog');
            document.body.appendChild(dialog);
        }
        dialog.render(options).then(dialog.open());

        return dialog;
    }

    static DIALOG_DEFAULT_OPTIONS = {
        modal: true, // is it a modal box. Default is true
        width: '680px',
        height: undefined,
        position: 'auto',
        title: null, // dialog title
        content: null, // content that appended to dialog
        url: null, // url to fetch content that appended to dialog, use content firstly
        beforeOpen: null, // callback before dialog open
        afterOpen: null, // callback after dialog open
        beforeClose: null, // callback before dialog close
        afterClose: null, // callback after dialog close
        closeWhenClickedOutside: false, // close the dialog when user clicked at the outside of the dialog
    };

    #dialog = null;
    #titleBar = null;
    #title = null;
    #closeBtn = null;
    #contentRoot = null;
    #options = null;

    constructor() {
        super();
        this.#renderDialog();
        this.#bindEvent();
    }

    open() {
        let self = this;
        if (self.#options.beforeOpen) {
            self.#options.beforeOpen.call(null, self);
        }
        if (self.#options.modal) {
            self.#dialog.showModal();
        } else {
            self.#dialog.show();
        }
        self.#dialog.style.display = 'flex';
        if (self.#options.afterOpen) {
            self.#options.afterOpen.call(null, self);
        }
    }

    close() {
        let self = this;
        if (self.#options.beforeClose) {
            self.#options.beforeClose.call(null, self);
        }
        self.#dialog.close();
        if (self.#options.afterClose) {
            self.#options.afterClose.call(null, self);
        }
        self.#contentRoot.innerHTML = '';
        JscDialog.#returnDialog(self);
    }

    fetchContainer() {
        return this.#contentRoot;
    }

    async render(options) {
        let self = this;
        self.#options = Object.assign({}, JscDialog.DIALOG_DEFAULT_OPTIONS, options);
        self.#title.innerHTML = self.#options.title;
        self.#dialog.style.width = self.#options.width;
        if (self.#options.height) {
            self.#dialog.style.height = self.#options.height;
        }
        self.#contentRoot.style.maxHeight = (window.innerHeight - 100) + 'px';

        let renderExecutor = function (content) {
            self.#contentRoot.innerHTML = content;
            let _position = self.#options.position;
            let containerStyle = window.getComputedStyle(self.#dialog);
            let windowWidth = window.innerWidth;
            if (typeof (_position) === 'string') {
                switch (_position.toUpperCase()) {
                    case 'AUTO':
                    default: {
                        let width = parseFloat(containerStyle.width);
                        if (containerStyle.width.indexOf('%') >= 0) {
                            width = windowWidth * width / 100;
                        }
                        if (width > windowWidth) {
                            self.#dialog.style.left = '0px';
                        } else {
                            self.#dialog.style.left = (windowWidth - width) / 2 + 'px';
                        }
                        let windowHeight = window.innerHeight;
                        let height = parseFloat(containerStyle.height);
                        if (containerStyle.height.indexOf('%') >= 0) {
                            height = windowHeight * height / 100;
                        }
                        if ((height + 200) > windowHeight) {
                            self.#dialog.style.top = '0px';
                            self.#dialog.style.height = windowHeight - 15 + 'px';
                        } else {
                            self.#dialog.style.top = '100px';
                        }
                    }
                }
            } else {
                self.#dialog.style.top = _position.top;
                self.#dialog.style.left = _position.left;
            }

            return self.#contentRoot;
        }
        if (null != self.#options.content && self.#options.content.length > 0) {
            return Promise.resolve(renderExecutor(self.#options.content))
        } else {
            return new Promise((resolve, reject) => {
                JscUtil.getText(self.#options.url)
                    .then(content => {
                        resolve(renderExecutor(content));
                    })
                    .catch(err => reject(err));

            });
        }
    }

    #bindEvent() {
        let self = this;
        self.#closeBtn.addEventListener('click', function (e) {
            self.close();
        });
        self.#dialog.addEventListener('click', function (e) {
            if (!self.#dialog.open) {
                return;
            }
            let area = window.getComputedStyle(self.#dialog);
            let top = Number.parseInt(area.top);
            let left = Number.parseInt(area.left);
            let width = Number.parseInt(area.width);
            let height = Number.parseInt(area.height);

            if (isNaN(width) || isNaN(top) || isNaN(left) || isNaN(height)) {
                return;
            } else {
                if (self.#options.closeWhenClickedOutside) {
                    if (e.clientX >= left && e.clientX <= left + width && e.clientY >= top && e.clientY <= top + height) {
                        return;
                    } else {
                        self.close();
                    }
                }
            }
        });
        self.#dialog.addEventListener('close', function (e) {
            self.#dialog.style.display = 'none';
        });
    }

    #renderDialog() {
        const shadowRoot = this.attachShadow({ mode: 'open' });
        shadowRoot.innerHTML = `
        <link rel='stylesheet' type='text/css' href='${JscConfig.cssUrl}'/>
        <dialog class="dialogContainer">
            <div class="dialogTitleBar">
                <span class="dialogTitle"></span>
                <span class="dialogCloseBtn" title="关闭"></span>
            </div>
            <div class="dialogContent"></div>
        </div>
        `;
        this.#dialog = this.shadowRoot.querySelector('.dialogContainer');
        this.#titleBar = this.shadowRoot.querySelector('.dialogTitleBar');
        this.#title = this.shadowRoot.querySelector('.dialogTitle');
        this.#closeBtn = this.shadowRoot.querySelector('.dialogCloseBtn');
        this.#contentRoot = this.shadowRoot.querySelector('.dialogContent');
    }
}

if (!customElements.get('jsc-dialog')) {
    window.customElements.define("jsc-dialog", JscDialog);
}

if (!window.Jsc) {
    window.Jsc = {};
}

Jsc.showDialog = JscDialog.show;